﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;

namespace OA.Core.Helper
{
    public static class EnumHelper
    {

        private static readonly ConcurrentDictionary<Type, Dictionary<int, string>> EnumNameValueDict = new ConcurrentDictionary<Type, Dictionary<int, string>>();
        private static readonly ConcurrentDictionary<Type, Dictionary<string, int>> EnumValueNameDict = new ConcurrentDictionary<Type, Dictionary<string, int>>();

        public static Dictionary<int, string> GetDictionary(Type enumType)
        {
            if (!enumType.IsEnum)
            {
                throw new Exception("给定的类型不是枚举类型");
            }

            var names = EnumNameValueDict.ContainsKey(enumType) ? EnumNameValueDict[enumType] : new Dictionary<int, string>();
            if (names.Count == 0)
            {
                names = GetDictionaryItems(enumType);
                EnumNameValueDict[enumType] = names;
            }

            return names;
        }

        private static Dictionary<int, string> GetDictionaryItems(Type enumType)
        {
            var enumItems = enumType.GetFields(BindingFlags.Public | BindingFlags.Static);
            var names = new Dictionary<int, string>(enumItems.Length);
            foreach (FieldInfo enumItem in enumItems)
            {
                int intValue = (int)enumItem.GetValue(enumType);
                names[intValue] = enumItem.Name;
            }

            return names;
        }



        public static TA GetAttribute<TA>(this object myenum)
            where TA : System.Attribute
        {
            Type enumType = myenum.GetType();
            if (!enumType.IsEnum)
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            object[] customAttributes = enumType.GetField(myenum.ToString()).GetCustomAttributes(typeof(TA), true);
            if (customAttributes.Length == 0)
            {
                return null;
            }
            return (TA)(customAttributes[0]);
        }

        public static TA GetEnumAttribute<TA>(this Enum myenum)
            where TA : System.Attribute
        {
            Type enumType = myenum.GetType();
            object[] customAttributes = enumType.GetField(myenum.ToString()).GetCustomAttributes(typeof(TA), true);
            if (customAttributes.Length == 0)
            {
                return null;
            }
            return (TA)(customAttributes[0]);
        }

        public static TA GetEnumAttribute<TA>(this object myenum, Type enumType)
            where TA : System.Attribute
        {
            if (!enumType.IsEnum)
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            object[] customAttributes = enumType.GetField(myenum.ToString()).GetCustomAttributes(typeof(TA), true);
            if (customAttributes.Length == 0)
            {
                return null;
            }
            return (TA)(customAttributes[0]);
        }

        /// <summary>
        /// Key:枚举名称,Value:枚举值
        /// </summary>
        public static Dictionary<string, int> GetEnumKeyValue<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var list = Enum.GetNames(enumType);
            return list.ToDictionary(enumName => enumName, enumName => (int)Enum.Parse(enumType, enumName));
        }

        /// <summary>
        /// Key:枚举值,Value:枚举名称
        /// </summary>
        public static Dictionary<int, string> GetEnumValueKey<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var list = Enum.GetNames(enumType);
            return list.ToDictionary(enumName => (int)Enum.Parse(enumType, enumName));
        }

        /// <summary>
        /// Key:枚举值,Value:属性
        /// </summary>
        public static Dictionary<int, TAttr> GetEnumAttributeAndValue<T, TAttr>()
            
            where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, TAttr>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                TAttr ta;
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(TAttr), true);
                if (customAttributes.Length == 0) ta = default(TAttr);
                else ta = (TAttr)customAttributes[0];
                enumDictionary.Add((int)Enum.Parse(enumType, enumName), ta);
            }
            return enumDictionary;
        }

        /// <summary>
        /// Key:枚举值,Value:属性
        /// </summary>
        public static Dictionary<int, TAttr> GetEnumAttributeAndValue<TAttr>(Type enumType)
            
        {
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, TAttr>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                TAttr ta;
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(TAttr), true);
                if (customAttributes.Length == 0) ta = default(TAttr);
                else ta = (TAttr)customAttributes[0];
                enumDictionary.Add((int)Enum.Parse(enumType, enumName), ta);
            }
            return enumDictionary;
        }

        /// <summary>
        /// Key:枚举值,Value:枚举描述
        /// </summary>
        public static Dictionary<int, string> GetEnumDescriptAndValue<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, string>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                string s;
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (customAttributes.Length == 0) s = string.Empty;
                else s = ((DescriptionAttribute)customAttributes[0]).Description;
                enumDictionary.Add((int)Enum.Parse(enumType, enumName), s);
            }
            return enumDictionary;
        }
        /// <summary>
        /// Key:枚举值,Value:枚举描述
        /// 未标记description属性将被忽略
        /// </summary>
        public static Dictionary<int, string> GetEnumDescriptionAndValue<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, string>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (customAttributes.Length > 0)
                    enumDictionary.Add((int)Enum.Parse(enumType, enumName), ((DescriptionAttribute)customAttributes[0]).Description);
            }
            return enumDictionary;
        }

        /// <summary>
        /// Key:枚举名称,Value:枚举描述
        /// </summary>
        public static Dictionary<string, string> GetEnumDescriptAndName<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<string, string>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                string s;
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(DescriptionAttribute), true);
                if (customAttributes.Length == 0) s = string.Empty;
                else s = ((DescriptionAttribute)customAttributes[0]).Description;
                enumDictionary.Add(enumName, s);
            }
            return enumDictionary;
        }
        /// <summary>
        /// Key:枚举值,
        /// Value:key:枚举名称，value:枚举描述
        /// </summary>
        public static Dictionary<int, KeyValuePair<string, string>> GetEnumKeyNameDescript<T>() where T : new()
        {
            Type enumType = typeof(T);
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, KeyValuePair<string, string>>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(DescriptionAttribute), true);
                enumDictionary.Add((int)Enum.Parse(enumType, enumName), new KeyValuePair<string, string>(enumName, customAttributes.Length == 0 ? string.Empty : ((DescriptionAttribute)customAttributes[0]).Description));
            }
            return enumDictionary;
        }

        public static Dictionary<string, int> GetEnumKeyValue(Type enumType)
        {
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must be System.Enum.");
            }
            var list = Enum.GetNames(enumType);
            return list.ToDictionary(enumName => enumName, enumName => (int)Enum.Parse(enumType, enumName));
        }

        public static Dictionary<int, string> GetEnumDescriptionAndValue(this Type enumType)
        {
            if (enumType == null) return new Dictionary<int, string>();
            if (enumType.BaseType != typeof(Enum))
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var enumDictionary = new Dictionary<int, string>();
            var list = Enum.GetNames(enumType);
            foreach (string enumName in list)
            {
                object[] customAttributes = enumType.GetField(enumName).GetCustomAttributes(typeof(DescriptionAttribute), false);
                if (customAttributes.Length > 0)
                    enumDictionary.Add((int)Enum.Parse(enumType, enumName), ((DescriptionAttribute)customAttributes[0]).Description);
            }
            return enumDictionary;
        }

        public static T[] ToArray<T>(Type enumType)
        {
            if (!enumType.IsEnum)
            {
                throw new ArgumentException("Type T must inherit from System.Enum.");
            }
            var list = Enum.GetNames(enumType);
            return (from r in Enum.GetNames(enumType)
                    select (T)Enum.Parse(enumType, r)).ToArray();
        }
    }
}
